package task

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"time"
)

type NetHandler struct {
	flow *FlowTask
}

func NewNetHandler(flow *FlowTask) *NetHandler {
	net := new(NetHandler)
	net.flow = flow
	return net
}

//RequestHttp 执行http数据请求
func (m *NetHandler) RequestHttp(node *Node) error {
	url := node.Content["url"]
	contentType := node.Content["contentType"]
	method := node.Content["method"]
	success := node.Content["success"]
	dataKey := node.Content["dataKey"]
	dataType := node.Content["dataType"]

	input := m.flow.BindInput(node.Params)
	var send io.Reader
	var getSend string
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	cli := &http.Client{Timeout: 10 * time.Second, Transport: tr}

	switch contentType {
	case "application/json;charset=utf-8":
		bs, err := json.Marshal(input)
		if err != nil {
			log.Println("执行HTTP：", err)
			return err
		}
		send = bytes.NewReader(bs)
	default:
		buf := bytes.Buffer{}
		num := len(input)
		for k, v := range input {
			buf.WriteString(k)
			buf.WriteString("=")
			buf.WriteString(v.(string))
			num--
			if num != 0 {
				buf.WriteString("&")
			}
		}
		getSend = buf.String()
	}
	var resp *http.Response
	var err error
	if method == "GET" {
		resp, err = cli.Get(url + "?" + getSend)
	} else {
		req, err := http.NewRequest(method, url, send)
		if err != nil {
			log.Println("执行HTTP请求创建Request失败", err)
			return err
		}
		req.Header.Set("Content-Type", contentType)
		resp, err = cli.Do(req)
	}
	if err != nil {
		log.Println("执行HTTP请求失败", err)
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("执行HTTP读取响应数据失败", err)
		return err
	}
	if dataType == "string" {
		m.flow.outText[node.Id] = string(body)
	} else {
		if success != "" {
			result := make(map[string]interface{}, 0)
			err = json.Unmarshal(body, &result)
			if err != nil {
				log.Println("执行HTTP读取响应数据格式转换失败", err)
				return err
			}
			ok, err := m.flow.Expression(success, "", result, nil)
			if err != nil {
				log.Println("执行HTTP响应结果失败", err)
				return err
			}
			if ok {
				if dataType == "list" {
					m.flow.outList[node.Id] = result[dataKey].([]map[string]interface{})
				} else if dataType == "object" {
					m.flow.out[node.Id] = result[dataKey].(map[string]interface{})
				}
			}
		} else {
			if dataType == "list" {
				result := make([]map[string]interface{}, 0)
				err = json.Unmarshal(body, &result)
				if err != nil {
					log.Println("执行HTTP读取响应数据格式转换失败", err)
					return err
				}
				m.flow.outList[node.Id] = result
			} else if dataType == "object" {
				result := make(map[string]interface{}, 0)
				err = json.Unmarshal(body, &result)
				if err != nil {
					log.Println("执行HTTP读取响应数据格式转换失败", err)
					return err
				}
				m.flow.out[node.Id] = result
			}
		}
	}
	return nil
}

//Upload 文件上传服务
func (m *NetHandler) Upload(node *Node) error {
	url := node.Content["url"]
	success := node.Content["success"]
	dataKey := node.Content["dataKey"]
	dataType := node.Content["dataType"]
	name := node.Content["name"]
	input := m.flow.BindInput(node.Params)
	bodyBuffer := &bytes.Buffer{}
	bodyWriter := multipart.NewWriter(bodyBuffer)
	data := input["sourceFile"]
	if data != nil {
		ds, ok := data.([]map[string][]byte)
		if ok {
			for _, item := range ds {
				for k, v := range item {
					fw, _ := bodyWriter.CreateFormFile(name, k)
					fw.Write(v)
				}
			}
		}
	}
	delete(input, "sourceFile")
	for key, value := range input {
		v, ok := value.(string)
		if !ok {
			continue
		}
		bodyWriter.WriteField(key, v)
	}
	contentType := bodyWriter.FormDataContentType()
	bodyWriter.Close()

	resp, err := http.Post(url, contentType, bodyBuffer)
	if err != nil {
		m.flow.errMsg = append(m.flow.errMsg, "文件上传请求："+err.Error())
		return err
	}
	defer resp.Body.Close()
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		m.flow.errMsg = append(m.flow.errMsg, "文件上传读取数据："+err.Error())
		return err
	}
	if dataType == "object" || dataType == "list" {
		result := make(map[string]interface{}, 0)
		err := json.Unmarshal(bs, &result)
		if err != nil {
			m.flow.errMsg = append(m.flow.errMsg, "文件上传响应："+err.Error())
			return err
		}
		ok, err := m.flow.Expression(success, "", result, nil)
		if err != nil || !ok {
			m.flow.errMsg = append(m.flow.errMsg, "文件上传验证响应结果："+err.Error())
			return err
		}
		if dataType == "object" {
			v, ok := result[dataKey].(map[string]interface{})
			if !ok {
				return nil
			}
			m.flow.out[node.Id] = v
		} else {
			v, ok := result[dataKey].([]map[string]interface{})
			if !ok {
				return nil
			}
			m.flow.outList[node.Id] = v
		}
	} else if dataType == "string" {
		m.flow.outText[node.Id] = string(bs)
	} else if dataType == "bytes" {
		m.flow.outByte[node.Id] = bs
	}
	return nil
}
